package com.spring;


import java.beans.Introspector;
import java.io.File;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Created By dm on 2023/11/27
 */
public class SpringDemoApplicationContext {


    private Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>();

    private Map<String /* beanName*/,Object/*实例对象*/> singletonObjects = new ConcurrentHashMap<>();


    public SpringDemoApplicationContext(Class appConfig) {
        scan(appConfig);


        instanceBean();

    }

    private void instanceBean() {
        for (String beanName : beanDefinitionMap.keySet()) {
            BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
            if (beanDefinition.getScope().equals(ScopeContants.singleton)) {
                // 单例bean，创建后存入容器
                Object bean = doCreateBean(beanName, beanDefinition);

                singletonObjects.put(beanName, bean);
            }
        }
    }

    private Object doCreateBean(String beanName, BeanDefinition beanDefinition) {
        Class clazz = beanDefinition.getType();
        try {
            // todo 构造推断（有参构造）
            Constructor declaredConstructor = clazz.getDeclaredConstructor();
            Object beanClass = declaredConstructor.newInstance();
            // 填充属性
            Field[] fields = beanClass.getClass().getDeclaredFields();
            for (Field field : fields) {

                // 依赖注入
                if (field.isAnnotationPresent(Autowired.class)) {
                    String fieldName = field.getName();
                    Object bean = getBean(fieldName);
                    field.setAccessible(true);
                    field.set(beanClass, bean);
                }

            }

            // Aware回调
            if (beanClass instanceof BeanNameAware) {
                ((BeanNameAware) beanClass).setBeanName(beanName);
            }

            // postProcessor执行
            return beanClass;

        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
        return null;
    }

    public Object getBean(String beanName) {
        if(singletonObjects.containsKey(beanName)){
            return singletonObjects.get(beanName);
        }
        BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
        return doCreateBean(beanName,beanDefinition);
    }


    public void scan(Class appConfig) {
        // 扫描
        if (appConfig.isAnnotationPresent(ComponentScan.class)) {
            ComponentScan componentScan = (ComponentScan) appConfig.getAnnotation(ComponentScan.class);
            String componentScanPath = componentScan.value();
            System.out.println("扫描路径：" + componentScanPath);
            // 扫描获取所有的class
            List<Class> beanClassList = getBeanClassList(componentScanPath);
            for (Class aClass : beanClassList) {
                if (aClass.isAnnotationPresent(Component.class)) {
                    BeanDefinition beanDefinition = new BeanDefinition();
                    Component component = (Component) aClass.getAnnotation(Component.class);
                    beanDefinition.setType(aClass);
                    // 如果未定义beanName，则直接进行生成
                    String beanName = component.value();
                    if ("".equals(beanName)) {
                        beanName = Introspector.decapitalize(aClass.getSimpleName());
                    }
                    // 解析scope
                    if (aClass.isAnnotationPresent(Scope.class)) {
                        Scope scope = (Scope) aClass.getAnnotation(Scope.class);
                        String scopeValue = scope.value();
                        if (ScopeContants.singleton.equals(scopeValue)) {
                            beanDefinition.setScope(ScopeContants.singleton);
                        } else {
                            beanDefinition.setScope(ScopeContants.prototype);
                        }
                    } else {
                        beanDefinition.setScope(ScopeContants.singleton);
                    }
                    beanDefinitionMap.put(beanName, beanDefinition);
                }
            }
        }
    }

    // 获取扫描包路径获取的beanList
    private List getBeanClassList(String componentScanPath) {
        List<Class> classList = new ArrayList<>();
        ClassLoader classLoader = SpringDemoApplicationContext.class.getClassLoader();
        componentScanPath = componentScanPath.replace(".", "/");
        URL resource = classLoader.getResource(componentScanPath);
        assert resource != null;
        File file = new File(resource.getFile());
        if (file.isDirectory()) {
            for (File f : file.listFiles()) {
                String fileName = f.getAbsolutePath();
                System.out.println(fileName);
                if (f.getName().endsWith(".class")) {
                    String className = fileName.substring(fileName.indexOf("com"), fileName.indexOf(".class"));
                    className = className.replace(File.separator, ".");
                    try {
                        Class<?> aClass = classLoader.loadClass(className);
                        classList.add(aClass);
                    } catch (ClassNotFoundException e) {
                        e.printStackTrace();
                    }
                }

            }
        }
        return classList;
    }
}
